package guava;

import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.hash.*;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.*;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

/**
 * Odds And Ends
 * User: Realfighter
 * Date: 2015/5/4
 * Time: 16:45
 */
public class OddsAndEndsTest {

    @Test
    public void testHashing() {
        HashFunction adler32 = Hashing.adler32();
        HashFunction crc32 = Hashing.crc32();

        HashFunction gfh = Hashing.goodFastHash(128);
        HashFunction murmur3_32 = Hashing.murmur3_32();
        HashFunction murmur3_128 = Hashing.murmur3_128();

        HashFunction sha1 = Hashing.sha1();
        HashFunction sha256 = Hashing.sha256();
        HashFunction sha512 = Hashing.sha512();

        BloomFilter<Book> bloomFilter = BloomFilter.create(BookFunnel.FUNNEL, 5);

    }

    @Test
    public void testBloomFilter() throws IOException {
        File booksPipeDelimited = new File("src/books.data");
        List<Book> books = Files.readLines(booksPipeDelimited,
                Charsets.UTF_8, new LineProcessor<List<Book>>() {
                    Splitter splitter = Splitter.on('|');
                    List<Book> books = Lists.newArrayList();
                    Book.Builder builder = new Book.Builder();

                    public boolean processLine(String line) throws IOException {
                        List<String> parts = Lists.newArrayList(splitter.split(line));
                        builder.author(parts.get(0))
                                .title(parts.get(1))
                                .publisher(parts.get(2))
                                .isbn(parts.get(3))
                                .price(Double.parseDouble(parts.get(4)));
                        books.add(builder.build());
                        return true;
                    }

                    @Override
                    public List<Book> getResult() {
                        return books;
                    }
                });
        BloomFilter<Book> bloomFilter = BloomFilter.create(BookFunnel.FUNNEL, 5);
        for (Book book : books) {
            bloomFilter.put(book);
        }
        Book newBook = new Book.Builder().title("Test Cook Book 2").build();
        Book book1 = books.get(0);
        System.out.println("book [" + book1.getTitle() + "] contained " + bloomFilter.mightContain(book1));
        System.out.println("book [" + newBook.getTitle() + "] contained " + bloomFilter.mightContain(newBook));
    }

    public enum BookFunnel implements Funnel<Book> {
        //This is the single enum value
        FUNNEL;

        public void funnel(Book from, PrimitiveSink into) {
            into.putBytes(from.getIsbn().getBytes(Charsets.UTF_8))
                    .putDouble(from.getPrice());
        }
    }

    @Test
    public void testOptionalOfInstance() {
        Book book = new Book.Builder().build();
        Optional<Book> bookOptional = Optional.of(book);
        assertThat(bookOptional.isPresent(), is(true));
    }

    @Test(expected = IllegalStateException.class)
    public void testOptionalNull() {
        Optional<Book> bookOptional = Optional.fromNullable(null);
        assertThat(bookOptional.isPresent(), is(false));
        bookOptional.get();
    }

    @Test
    public void testGetCausalChain() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        List<Throwable> throwAbles = null;
        Callable<FileInputStream> fileCallable = new Callable<FileInputStream>() {
            @Override
            public FileInputStream call() throws Exception {
                return new FileInputStream("Bogus file");
            }
        };
        Future<FileInputStream> fisFuture = executor.submit(fileCallable);
        try {
            fisFuture.get();
        } catch (Exception e) {
            throwAbles = Throwables.getCausalChain(e);
        }
        assertThat(throwAbles.get(0).getClass().isAssignableFrom(ExecutionException.class), is(true));
        assertThat(throwAbles.get(1).getClass().isAssignableFrom(FileNotFoundException.class), is(true));
        executor.shutdownNow();
    }

    @Test
    public void testGetRootCause() throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Throwable cause = null;
        final String nullString = null;
        Callable<String> stringCallable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return nullString.substring(0, 2);
            }
        };
        Future<String> stringFuture = executor.submit(stringCallable);
        try {
            stringFuture.get();
        } catch (Exception e) {
            cause = Throwables.getRootCause(e);
        }
        assertThat(cause.getClass().isAssignableFrom(NullPointerException.class), is(true));
        executor.shutdownNow();
    }
}


